import random
import re

from flask import request, jsonify, current_app, make_response, g, session
from info.utils.captcha import captcha
from modules import redis_store, constants, db
from modules.commons import user_login_data
from modules.home import my_blue
from modules.models import User
from modules.utils.response_code import RET


@my_blue.route('/imagecode')
def get_image_code():
    """
    功能：获取图片验证码
    请求路径：/api/v1.0/imagecode
    请求方式：GET
    请求参数：cur、pre
    步骤：
        - 1.获取参数，进行校验
        - 2.判断redis中是否有图片验证码，没有则调用第三方SDK生成图片验证码
        - 3.将图片验证码保存到redis，并删除前一张图片验证码
        - 4.返回响应及数据
    :return: image
    """
    # 1.获取参数，进行校验
    cur = request.args.get('cur')
    pre = request.args.get('pre')
    if not cur:
        return jsonify(errno=RET.PARAMERR, errmsg='参数不能为空')

    # 2.调用第三方SDK生成图片验证码,将图片验证码保存到redis
    name, text, image_code = captcha.captcha.generate_captcha()
    try:
        # 存储格式：key、value、有效期
        redis_store.set('image_code:%s' % cur, text, constants.IMAGE_CODE_REDIS_EXPIRES)

        # 3.删除前一张图片验证码
        if pre:
            redis_store.delete('image_code:%s' % pre)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='图片验证码存储或删除失败')

    # 4.返回响应及数据
    response = make_response(image_code)
    response.headers['Content-Type'] = 'image/png'
    return response


@my_blue.route('/smscode', methods=['POST'])
def get_sms_code():
    """
    功能：获取短信验证码
    请求路径：/api/v1.0/smscode
    请求方式：POST
    请求参数：mobile、image_code、image_code_id
    步骤：
        - 1.获取参数，进行校验
        - 2.通过image_code_id从redis中取出图片验证码，进行校验
        - 3.生成短信验证码，保存到redis中,返回响应
    :return: 响应状态
    """
    # 1.获取参数，进行校验
    mobile = request.json.get('mobile')
    image_code = request.json.get('image_code')
    image_code_id = request.json.get('image_code_id')
    if not all([mobile, image_code, image_code_id]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不全')
    if not re.match(r'1[3-9]\d{9}', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号码格式有误')

    # 2.通过image_code_id从redis中取出图片验证码，进行校验,最后删除
    try:
        redis_image_code = redis_store.get('image_code:%s' % image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='获取图片验证码失败')
    if not redis_image_code:
        return jsonify(errno=RET.NODATA, errmsg='图片验证码失效')
    if image_code.upper() != redis_image_code.upper():
        return jsonify(errno=RET.PARAMERR, errmsg='图片验证码错误')
    try:
        redis_store.delete('image_code:%s' % image_code_id)
    except Exception as e:
        current_app.logger.err(e)
        return jsonify(errno=RET.DBERR, errmsg='删除图片验证码失败')

    # 3.生成短信验证码，保存到redis中,返回响应
    sms_code = '%06d' % random.randint(0, 999999)
    try:
        redis_store.set('sms_code:%s' % mobile, sms_code, constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='短信验证码保存失败')
    print('短信验证码是——>{}'.format(sms_code))
    return jsonify(errno=RET.OK, errmsg='短信验证码发送成功')


@my_blue.route('/user', methods=['GET', 'POST'])
@user_login_data
def user_register():
    """
    功能：用户注册
    请求路径：/api/v1.0/user
    请求方式：POST
    请求参数：mobile、phonecode、password
    步骤：
        - 1.获取参数，进行校验
        - 2.判断短信验证码是否正确
        - 3.创建用户对象，设置属性，将密码加密，并保存到mysql中
        - 4.返回响应
    :return: 响应状态
    """
    if request.method == 'POST':
        # 1.获取参数，进行校验
        mobile = request.json.get('mobile')
        phone_code = request.json.get('phonecode')
        password = request.json.get('password')
        if not all([mobile, phone_code, password]):
            return jsonify(errno=RET.PARAMERR, errmsg='参数不全')

        # 2.判断短信验证码是否正确
        try:
            sms_code = redis_store.get('sms_code:%s' % mobile)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='获取短信验证码失败')
        if phone_code != sms_code:
            return jsonify(errno=RET.DATAERR, errmsg='短信验证码错误')

        # 3.创建用户对象，设置属性，将密码加密，并保存到mysql中
        user = User()
        user.name = mobile
        user.mobile = mobile
        user.password = password
        try:
            db.session.add(user)
            db.session.commit()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='用户注册失败')

        # 4.返回响应
        return jsonify(errno=RET.OK, errmsg='用户创建成功')
    if request.method == 'GET':
        data = {
            'avatar_url': g.user.avatar_url,
            'mobile': g.user.mobile,
            'name': g.user.name
        }
        return jsonify(errno=RET.OK, errmsg='获取用户信息成功', data=data)


@my_blue.route('/session', methods=['GET', 'POST', 'DELETE'])
@user_login_data
def user_login():
    """
    功能：用户登录、退出登录、获取登录状态
    请求路径：/api/v1.0/session
    请求方式：POST
    请求参数：mobile、password
    步骤：
        - 1.用户获取登录状态时，携带用户数据，返回响应
        - 2.用户登录时，获取参数，进行校验，验证通过则设置session
        - 3.用户退出登录时，清除session信息

    :return: 响应状态
    """
    # 1.用户获取登录状态时，携带用户数据，返回响应
    if request.method == 'GET':
        data = {
            'user_id':g.user.id,
            'name':g.user.name
        }
        return jsonify(errno=RET.OK, data=data)
    elif request.method == 'POST':
        mobile = request.json.get('mobile')
        password = request.json.get('password')
        if not all([mobile, password]):
            return jsonify(errno=RET.PARAMERR, errmsg='参数不全')
        try:
            user = User.query.filter(User.mobile == mobile).first()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='获取用户失败')
        if not user:
            return jsonify(errno=RET.NODATA, errmsg='用户不存在')
        if user.check_password(password):
            return jsonify(errno=RET.DATAERR, errmsg='密码错误')
        # 设置session，保存登录状态
        session['user_id'] = user.id
        return jsonify(errno=RET.OK, errmsg='登录成功')
    else:
        session['user_id'] = ''
        return jsonify(errno=RET.OK, errmsg='退出成功')
